package com.property.manage.service.flowingWater;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.guardchina.framework.mybatis.model.CustomPage;
import com.guardchina.framework.util.exception.BusinessException;
import com.guardchina.framework.util.exception.SystemException;
import com.guardchina.framework.util.utils.DateUtil;
import com.guardchina.framework.util.utils.NumberToCn;
import com.property.manage.dao.flowingWater.ArrearsDetailMapper;
import com.property.manage.model.flowingWater.ArrearsDetailEntity;
import com.property.manage.model.flowingWater.ArrearsVo;
import com.property.manage.model.flowingWater.FlowingWaterEntity;
import com.property.manage.model.flowingWater.TotalVo;
import com.property.manage.model.owner.OwnerEntity;
import com.property.manage.model.print.ArrearsPayBillVo;
import com.property.manage.model.resource.Building;
import com.property.manage.model.system.User;
import com.property.manage.model.village.Village;
import com.property.manage.service.owner.OwnerService;
import com.property.manage.service.resource.BuildingService;
import com.property.manage.service.system.SnowflakeIdWorker;
import com.property.manage.service.system.UserService;
import com.property.manage.service.village.VillageService;
import com.property.manage.util.DateUtilPlus;
import com.property.manage.util.ExportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author lwb
 **/
@Component
@Slf4j
public class ArrearsDetailService {
    @Autowired
    private ArrearsDetailMapper arrearsDetailMapper;
    @Autowired
    private WalletService walletService;
    @Autowired
    private FlowingWaterService flowingWaterService;
    @Autowired
    private UserService userService;
    @Autowired
    private VillageService villageService;
    @Autowired
    private BuildingService buildingService;
    @Autowired
    private OwnerService ownerService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Value("${timed.patee}")
    private String patee;

    @Value("${daily.running.arrears}")
    private String arrearsTemplateFile;

    @Value("${timed.receiveUnit}")
    private String receiveUnit;


    public int add(Integer buildingId, String listOfCharges, BigDecimal shouldPay, BigDecimal deductionAmount, BigDecimal ownMoney, LocalDate startDate, LocalDate endDate, String remark){
        ArrearsDetailEntity entity = new ArrearsDetailEntity();
        entity.setBuildingId(buildingId);
        entity.setListOfCharges(listOfCharges);
        entity.setShouldPay(shouldPay);
        entity.setDeductionAmount(deductionAmount);
        entity.setOwnMoney(ownMoney);
        entity.setStartDate(startDate);
        entity.setEndDate(endDate);
        entity.setState(ArrearsDetailEntity.STATE_NOT_PAY);
        entity.setCreateTime(DateUtilPlus.getCurrentLocalDateTime());
        entity.setRemark(remark);

        arrearsDetailMapper.insert(entity);

        return entity.getId();
    }

    public CustomPage<ArrearsVo> page(Long pageNo, Long pageSize, Integer villageId,  Integer building, Integer unit, String roomNumber){
        Page<ArrearsVo> page = new Page<>(pageNo, pageSize);

        IPage<ArrearsVo> result = arrearsDetailMapper.page(page, villageId, building, unit, roomNumber);

        List<ArrearsVo> arrearsVos = result.getRecords().stream().peek(arrearsVo -> arrearsVo.setBalance(walletService.findBalance(arrearsVo.getBuildingId(), null))).collect(Collectors.toList());


        return new CustomPage<>(result, arrearsVos);
    }

    public Integer arrearsCount(Integer villageId){
        return arrearsDetailMapper.arrearsCount(villageId);
    }

    public List<ArrearsDetailEntity> detailList(Integer buildingId) {

        QueryWrapper<ArrearsDetailEntity> wrapper = new QueryWrapper<>();

        wrapper.eq("building_id", buildingId);
        wrapper.eq("state", ArrearsDetailEntity.STATE_NOT_PAY);
        wrapper.orderByDesc("id");

        return arrearsDetailMapper.selectList(wrapper);
    }



    public ArrearsPayBillVo charge(Integer userId, Integer buildingId, String arrearsIds, BigDecimal totalMoney, BigDecimal deductionAmount, BigDecimal chargeMoney, String payType, Boolean useStorage, Boolean storageReturn, Boolean print, String remark) {

        log.info("物业费欠费收取：userId[{}], buildingId[{}], arrearsIds[{}], totalMoney[{}], deductionAmount[{}], chargeMoney[{}], payType[{}], useStorage[{}], storageReturn[{}], print[{}], remark[{}]", userId, buildingId, arrearsIds, totalMoney, deductionAmount, chargeMoney, payType, useStorage, storageReturn, print, remark);


        //实付金额
        BigDecimal realAmount = totalMoney.subtract(deductionAmount);
        if(realAmount.compareTo(BigDecimal.ZERO) < 0){
            throw new BusinessException("实付金额小于0");
        }

        Building building = buildingService.findBuilding(buildingId);
        Village village = villageService.findVillage(building.getVillageId());

        List<Integer> arrearsIdList = new Gson().fromJson(arrearsIds, new TypeToken<List<Integer>>(){}.getType());

        List<ArrearsDetailEntity> arrearsList = getList(arrearsIdList);

        BigDecimal shouldPayAmount = arrearsList.stream().map(ArrearsDetailEntity::getShouldPay).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);



        String explain = "欠费收取：" + arrearsList.stream().map(arrears -> {
            String dateStr = DateUtil.fromLocalDate(arrears.getStartDate());

            return dateStr.substring(0, 7);
        }).reduce((s1, s2) -> s1 + "、" + s2).orElse("");





        //减免金额从前端传入(减免金额需要改动)
        //BigDecimal deductionAmount = arrearsList.stream().map(ArrearsDetailEntity::getDeductionAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);


        /*if(totalMoney.compareTo(shouldPayAmount) != 0){
            throw new SystemException("总计金额不一致",String.format("shouldPayAmount[%s]", shouldPayAmount));
        }*/


        //转存预存,默认为零
        BigDecimal advanceReturn = BigDecimal.ZERO;
        //使用预存，默认为零
        BigDecimal advanceUse = BigDecimal.ZERO;
        //收款剩余金额
        BigDecimal remainMoney = chargeMoney.subtract(realAmount);
        //获取预存余额
        BigDecimal balance = walletService.findBalance(buildingId, null);

        //如果收款剩余金额大于等于0,且转存，则转存金额为收款剩余金额
        if(remainMoney.compareTo(BigDecimal.ZERO) >= 0 && storageReturn){
            advanceReturn = remainMoney;
        }else if (remainMoney.compareTo(BigDecimal.ZERO) < 0){
            //收款剩余金额小于零，且使用预存
            if(useStorage){
                //预存余额不足
                if(balance.add(remainMoney).compareTo(BigDecimal.ZERO) < 0){
                    throw new BusinessException("缴费金额不足",String.format("使用预存，预存余额[%s], 剩余缴费[%s]", balance, remainMoney.abs()));
                }else {
                    //使用的预存为，剩余的未缴费用
                    advanceUse = remainMoney.abs();
                }
            }else {
                throw new BusinessException("缴费金额不足",String.format("不使用预存，剩余缴费[%s]", remainMoney.abs()));
            }
        }

        if(advanceReturn.compareTo(BigDecimal.ZERO) > 0){
            walletService.changeDeposit(buildingId, advanceReturn, null);
        }

        if(advanceUse.compareTo(BigDecimal.ZERO) > 0){
            walletService.updateExpenditure(buildingId, advanceUse, null);
        }

        //缴费后的预存金额
        BigDecimal currentBalance = walletService.findBalance(buildingId, null);

        User user = userService.getUser(userId);

        String billNo = snowflakeIdWorker.nextId() + "";

        FlowingWaterEntity flowingWaterEntity = flowingWaterService.createFlowingWaterEntity(user, building, shouldPayAmount, realAmount, deductionAmount, advanceUse, currentBalance, chargeMoney, advanceReturn, "物业管理费", 1, explain, remark,payType, billNo, FlowingWaterEntity.OTHER_TYPE_ARREARS);
        flowingWaterEntity.setWalletType("PROPERTY");

        Integer flowWaterEntityId = flowingWaterService.save(flowingWaterEntity);

        charge(arrearsIdList, flowWaterEntityId, deductionAmount);

        if(print){
            ArrearsPayBillVo bill = new ArrearsPayBillVo();
            OwnerEntity ownerEntity = ownerService.findByBuilding(buildingId);


            bill.setTitle(patee + "收款收据");
            bill.setBillNo(billNo);
            bill.setVillageName(village.getName());
            bill.setAddress(buildingService.findAddress(building));
            bill.setOwnerName(ownerEntity.getOwnerName());
            bill.setPayTime(LocalDate.now());
            bill.setRemark(remark);
            bill.setPayee(user.getUserName());
            bill.setReceiveUnit(receiveUnit);

            List<ArrearsPayBillVo.BillDetail> billDetails = arrearsList.stream().map(arrears -> {
                ArrearsPayBillVo.BillDetail billDetail = new ArrearsPayBillVo.BillDetail();

                billDetail.setFeeType("物业费");
                billDetail.setStartEndDate(DateUtil.fromLocalDate(arrears.getStartDate()) + "-" + DateUtil.fromLocalDate(arrears.getEndDate()));
                billDetail.setUnitPrice(village.getPropertyMoney());
                billDetail.setShouldPay(arrears.getShouldPay());
                billDetail.setMoney(arrears.getOwnMoney());
                billDetail.setZnj(BigDecimal.ZERO);
                billDetail.setSubTotal(arrears.getOwnMoney());
                billDetail.setRemark("欠费缴纳");

                return billDetail;
            }).collect(Collectors.toList());

            bill.setBillDetails(billDetails);

            bill.setTotalAmount(shouldPayAmount);
            bill.setReceiveAmount(shouldPayAmount.subtract(deductionAmount));
            bill.setDeductionAmount(deductionAmount);
            bill.setPreAmount(balance);
            bill.setThisAmount(advanceUse);
            bill.setReturnAmount(currentBalance);
            bill.setRealAmount(chargeMoney);
            bill.setChineseAmount(NumberToCn.number2Cn(chargeMoney));


            return bill;
        }else{
            return null;
        }
    }

    public void undoCharge(Integer flowWaterEntityId){
        UpdateWrapper<ArrearsDetailEntity> wrapper = new UpdateWrapper<>();
        wrapper.eq("flowing_water_id", flowWaterEntityId);
        wrapper.set("state", ArrearsDetailEntity.STATE_NOT_PAY);

        arrearsDetailMapper.update(null, wrapper);
    }

    private void charge(List<Integer> arrearsIdList, Integer flowWaterEntityId, BigDecimal totalDeductionAmount) {
        UpdateWrapper<ArrearsDetailEntity> wrapper = new UpdateWrapper<>();
        wrapper.in("id", arrearsIdList);

        wrapper.set("state", ArrearsDetailEntity.STATE_PAID);
        wrapper.set("flowing_water_id", flowWaterEntityId);
        wrapper.set("real_deduction_amount", totalDeductionAmount.divide(new BigDecimal(arrearsIdList.size()), 2, RoundingMode.HALF_UP));

        //更新缴费时间
        String chargeTime = DateFormatUtils.format(new Date(), "yyyy-MM");
        wrapper.set("charge_time", chargeTime);
        arrearsDetailMapper.update(null, wrapper);
    }

    private List<ArrearsDetailEntity> getList(List<Integer> arrearsIdList) {

        QueryWrapper<ArrearsDetailEntity> wrapper = new QueryWrapper<>();
        wrapper.in("id", arrearsIdList);
        return arrearsDetailMapper.selectList(wrapper);
    }


    public TotalVo find(Integer villageId,String startTime, String endTime){
        List<Integer> integers = buildingService.selectByVillageId(villageId);
        log.info("id集合是{}",integers);
        TotalVo count =null;
        try{
            count = arrearsDetailMapper.getCount(startTime,endTime,integers);
        }catch (Exception e){
            log.info("错误{}",String.valueOf(e));
        }
        return count;
    }

    public void export(Integer villageId, Integer building, Integer unit, String roomNumber, HttpServletRequest request, HttpServletResponse response){
        try {

            List<ArrearsVo> list = arrearsDetailMapper.list(villageId, building, unit, roomNumber);

            XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(arrearsTemplateFile));

// 根据页面index 获取sheet页

            XSSFSheet sheet = wb.getSheetAt(0);

            for (int i = 0; i < list.size(); i++) {
                ArrearsVo arrearsVo = list.get(i);
                XSSFRow rw = sheet.createRow(i + 1);
                setCell(arrearsVo, rw);

            }

            String fileName = "欠费记录.xlsx";


            ExportUtil.exportExcel(request, response, fileName, wb);

        } catch (Exception e) {

            throw new SystemException("下载失败", e);

        }
    }

    private void setCell(ArrearsVo arrearsVo, XSSFRow row) {

        row.createCell(0).setCellValue(arrearsVo.getVillageName());
        row.createCell(1).setCellValue(arrearsVo.getBuilding()+"栋-" + arrearsVo.getUnit()+"单元-" + arrearsVo.getRoomNumber());
        row.createCell(2).setCellValue(arrearsVo.getOwnerName());
        row.createCell(3).setCellValue(arrearsVo.getOwnMoney().setScale(2, RoundingMode.HALF_UP).doubleValue());
        row.createCell(4).setCellValue(arrearsVo.getOwnNumber());
    }
}
